﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace Milkify.Views
{
    /// <summary>
    /// Interaction logic for KeyboardShortcutControl.xaml
    /// </summary>
    [System.Windows.Markup.ContentProperty("Text")]
    public partial class KeyboardShortcutControl : UserControl
    {
        public static readonly DependencyProperty TextProperty;
        public static readonly RoutedEvent TextChangedEvent;

        static KeyboardShortcutControl()
        {
            var metadata = new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnTextPropertyChanged, CoerceText, true, UpdateSourceTrigger.PropertyChanged);
            TextProperty = TextBox.TextProperty.AddOwner(typeof(KeyboardShortcutControl), metadata);
            
            TextChangedEvent = TextBox.TextChangedEvent.AddOwner(typeof(KeyboardShortcutControl));
        }

        private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            KeyboardShortcutControl ksc = (KeyboardShortcutControl)d;
            ksc.RaiseEvent(new RoutedEventArgs(TextChangedEvent));
        }

        private static object CoerceText(DependencyObject d, object value)
        {
            if (value == null)
                return string.Empty;
            return value;
        }

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public event RoutedEventHandler TextChanged
        {
            add { AddHandler(TextChangedEvent, value); }
            remove { RemoveHandler(TextChangedEvent, value); }
        }

        public KeyboardShortcutControl()
        {
            InitializeComponent();

            TextShortcut.KeyDown += new KeyEventHandler(KeyboardShortcutBox_KeyDown);
            TextShortcut.KeyUp += new KeyEventHandler(KeyboardShortcutBox_KeyUp);
        }

        protected override void OnContentChanged(object oldContent, object newContent)
        {
            if (oldContent != null)
                throw new InvalidOperationException("The content of this control can't be changed.");
            base.OnContentChanged(oldContent, newContent);
        }

        private void KeyboardShortcutBox_KeyDown(object sender, KeyEventArgs e)
        {
            UpdateShortcutText(e.Key);
            e.Handled = true;
        }

        private void KeyboardShortcutBox_KeyUp(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void UpdateShortcutText(Key key)
        {
            StringBuilder text = new StringBuilder();
            if (GetModifier(ModifierKeys.Control))
                text.Append("Ctrl + ");
            if (GetModifier(ModifierKeys.Alt))
                text.Append("Alt + ");
            if (GetModifier(ModifierKeys.Shift))
                text.Append("Shift + ");
            if (GetModifier(ModifierKeys.Windows) || 
                Keyboard.GetKeyStates(Key.LWin) == KeyStates.Down || 
                Keyboard.GetKeyStates(Key.RWin) == KeyStates.Down)
                text.Append("Windows + ");

            if (IsNonModifierKey(key))
                text.Append(key.ToString());

            Text = text.ToString();
        }

        private bool GetModifier(ModifierKeys modifier)
        {
            return ((Keyboard.Modifiers & modifier) == modifier);
        }

        private bool IsNonModifierKey(Key key)
        {
            switch (key)
            {
                case Key.LWin:
                case Key.LeftAlt:
                case Key.LeftCtrl:
                case Key.LeftShift:
                case Key.RWin:
                case Key.RightAlt:
                case Key.RightCtrl:
                case Key.RightShift:
                case Key.System:
                    return false;
                default:
                    return true;
            }
        }
    }
}
